/******************************************************************************/
/* File: socketClass.h                                                        */
/******************************************************************************/
/* This source code file is a header file for a series of C++ classes that    */
/* encapsulate the socket libraries to provide network functionality.  The    */
/* C++ classes wrap the C function calls to provide the same functionality to */
/* object oriented programmers.                                               */
/******************************************************************************/

/******************************************************************************/
/* Check to see if already included.                                          */
/******************************************************************************/
#ifndef SOCKETCLASS_H
#define SOCKETCLASS_H

/******************************************************************************/
/**注意:***********************************************************************/
/* 既可以在类的声明中，也可以在函数定义中声明缺省参数，但不能既在类声明中又在函数定义*/
/* 中同时声明缺省参数。                                                         */
/******************************************************************************/

/******************************************************************************/
/* Include definitions required to define classes.                            */
/******************************************************************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <iostream>

#include "cjson.h"

/******************************************************************************/
/* class SocketException.                                                     */
/*                                                                            */
/* This class is used to store the exception details when an error occurs.    */
/* When any class method call in the socketcc library fails, it throws an     */
/* instance of SocketException, this can be caught and queried for the actual */
/* error code. The exception can be cast to either the error code or a char   */
/* pointer for a textual description of the error.                            */
/******************************************************************************/
class SocketException {

public:
    enum ErrorCodes { 
        errBadHostName = 0, 
        errNoIPAddress,
        errDNSError,
        errNoProtocolSupport, 
        errKernelMemory,
        errNoDescriptors,
        errPermissionDenied,
        errMemory,
        errInvalidProtocol,
        errBadDescriptor,
        errIllegalPointer,
        errAlreadyConnected,
        errConnectRefused,
        errConnectTimeOut,
        errNetUnreachable,
        errAddrInUse,
        errInProgress,
        errAlreadyConnecting,
        errIncorrectAddrFamily,
        errBrdCastNotEnabled,
        errAlreadyBound,
        errAddressProtected,
        errCantListen,
        errNotStreamSock,
        errNoPendingConnections,
        errFirewall,
        errNotConnected,
        errWouldBlock,
        errInterrupted,
        errInvalidArgument,
        errMessageSizeTooBig,
        errNotBound,
        errOptionNotSupported,
        errUnknown,
    };

    //Default: ErrorCodes ecType = errUnknown
    SocketException(ErrorCodes ecType);
    SocketException(const SocketException &cOriginal);
    ~SocketException();
    
    void PrintException();
    bool CompareErrCode(enum ErrorCodes ec);

    operator const ErrorCodes() { 
        return ecException; 
    }
    
    operator const char*() { 
        return pcExceptionString; 
    }

private:
    // The error code.
    ErrorCodes ecException;
    
    // The string information of the exception.
    char *pcExceptionString;
    
    // Private function. Call this function to meet the demand of exception description obtain.
    void SetString(const char *pcErrString);
};

/******************************************************************************/
/* class IPAddress.                                                           */
/*                                                                            */
/* This class is used to provide transparent IPv4 and IPv6 address support    */
/* for the Socket classes within the library.  The constructor creates a      */
/* default IPv4 address to localhost.  The address can be assigned and parts  */
/* of the address can be extracted for usage.  This class is intended to be   */
/* used in conjunction with the Socket classes.  The member methods are:      */
/*                                                                            */
/* operator=          : Assignment of an IPAddress class.  Can be either from */
/*                      an existing IPAddress class, a string representing an */
/*                      IPv4 host name, an IPv4 address in an in_addr struct  */
/*                      or an IPv6 address in an in6_addr struct.             */
/* operator==         : Check equality of an IPAddress class.  Can be compared*/
/*                      against another IPAddress class, a string host name,  */
/*                      or addresses stored in an in_addr or in6_addr structs.*/
/* SetHostName()      : Sets an IPAddress by providing a host name and a      */
/*                      boolean variable to indicate whether we want an IPv6  */
/*                      or IPv4 address.                                      */
/* SetAddress()       : Sets an IPAddress by providing a pointer to an address*/
/*                      structure of the form in_addr or in6_addr.  This      */
/*                      pointer is cast to (char *).  A boolean value is used */
/*                      to indicate if this points to an IPv6 or IPv4 address.*/
/* GetAddressFamily() : Returns a constant integer of the address family      */
/*                      represented by the IPAddress.                         */
/* GetHostName()      : Returns a constant string pointer to the hostname of  */
/*                      the represented IP Address.                           */
/* Get_in_addr()      : Returns a (void *) to the address represented by      */
/*                      IPAddress.  This must be cast to (in_addr *) or to    */
/*                      (in6_addr *) for use.                                 */
/* GetAddressString() : Returns a constant string pointer to the string       */
/*                      representation of the IP Address suitable for visual  */
/*                      presentation.                                         */
/******************************************************************************/
class IPAddress {

public:
    IPAddress();
    ~IPAddress();
    
    // '=' assignment operator must be overrided.
    IPAddress & operator = (const IPAddress &cOrigAddr);
    IPAddress & operator = (const char *pcHostName);
    IPAddress & operator = (const struct in_addr sIP4Addr);
    IPAddress & operator = (const struct in6_addr sIP6Addr);

    // '==' equal comparison operator must be overrided.
    bool operator == (const IPAddress &cOtherAddr) const;
    bool operator == (const char *pcHostName) const;
    bool operator == (const struct in_addr sIP4Addr) const;
    bool operator == (const struct in6_addr sIP6Addr) const;

    void SetHostName(const char *pcNewHostName, bool bIPv6);
    void SetAddress(const char *pcNewAddress, bool bIPv6);
    
    operator char*() { 
        return pcHostName; 
    }

    const int GetAddressFamily() { 
        return iAddressType;
    }
    
    const char* GetHostName() {
        return pcHostName;
    }
    
    const void* Get_in_addr() { 
        return (void *)pcAddress; 
    }
    
    const int Get_in_addr_length() { 
        return iAddressLength;
    }
    
    const char* GetAddressString() { 
        return pcStrAddress;
    }
    
private:
    // ipv4 or ipv6?
    int  iAddressType;
    
    // 4B for ipv4, 16B for ipv6.
    int  iAddressLength;
    
    // Simply store the host name, such as "localhost".
    char *pcHostName;
    
    // pcAddress is used to save the ipAddress.
    // For ipv4 address which is 32-bit length, that is 4 Byte(4 char);
    // For ipv6 address which is 128-bit length, that is 16 Byte(16 char).
    // Therefore, pcAddress can content both ipv4 and ipv6 address.
    char pcAddress[16];
    
    // pcStrAddress is the string-format ip address.
    char pcStrAddress[INET6_ADDRSTRLEN];

    // Mutex lock which is used for multi-threading condition.
    static pthread_mutex_t  mutexKernelLock;

    void privSetHostName(const char *pcNewHostName);
    void privSetAddress(const char *pcNewAddress, const int iNewAddressLength);
};

/******************************************************************************/
/* class SocketBase.                                                          */
/*                                                                            */
/* This class is used to provide basic IP socket functionality within a C++   */
/* class environment.  The socket descriptor is stored as a member variable   */
/* within the socket class.  The member methods are simple wrappers to the    */
/* stadard socket library function calls except they use IPAddress instances  */
/* and port numbers rather than sockaddr structures.  Also, the methods throw */
/* exceptions when errors occur allowing for affirmative programming within a */
/* try block.  The provided methods are as follows:                           */
/*                                                                            */
/* constructor   : Create either an IPv4 or IPv6 socket.  The default socket  */
/*                 type is SOCK_STREAM or TCP.  A second constructor allows a */
/*                 class instance to be created to represent a socket where   */
/*                 a socket descriptor already exists.                        */
/* destructor    : Destroy the created socket.                                */
/* Connect()     : Connect the socket to the specified IP Address and port    */
/*                 number.                                                    */
/* Bind()        : Bind the local socket to the provided details, there are   */
/*                 methods.  If the IP Address is specified then bind to that */
/*                 IP Address, otherwise bind to the wildcard IP Address.     */
/*                 The default port number of 0 specifies for the operating   */
/*                 system to choose the port number.                          */
/* Listen()      : The socket to begin listening for connections, specifying  */
/*                 the maximum number of pending connections.                 */
/* Accept()      : Accept a pending connection, the SocketBase pointed to by  */
/*                 the provided parameter is modified to refer to the newly   */
/*                 connected socket.  The remote IP Address and port number   */
/*                 are also returned.                                         */
/* Recv()        : Receive data into a buffer from the socket.                */
/* RecvFrom()    : Receive data into a buffer from the socket, the IP Address */
/*                 and port number of the sender are also returned.           */
/* Send()        : The socket transmits the data to the remote socket.        */
/* SendTo()      : The socket transmits the data payload to the specified IP  */
/*                 address and port number.                                   */
/* GetSockName() : Get details of the IP address and port number bound to the */
/*                 local socket.                                              */
/* GetPeerName() : Get details of the IP address and port number bound to the */
/*                 remote socket.                                             */
/* GetSockOpt()  : Get current option settings on the socket.  Needs the code */
/*                 level and option name (same parameters as for getsockopt() */
/*                 call).  Returns current setting of option and size of data.*/
/* SetSockOpt()  : Set current option settings on the socket.  Needs the code */
/*                 level and option name (same parameters as for setsockopt() */
/*                 call) as well as new value for the option.                 */
/******************************************************************************/
class SocketBase {

public:
    // Default: bool bSocketIsIPv6 = false, int iSocketType = SOCK_STREAM
    SocketBase(bool bSocketIsIPv6, int iSocketType);
    virtual ~SocketBase();
    
    // Get and Set socket fd.
    int GetSockDesc();
    void SetSockDesc(int iNewFd);
    
    void Connect(IPAddress &cServAddr, int iServPortNo);
    
    // Default: IPAddress &cLocalAddr, int iLocalPort = 0
    void Bind(IPAddress &cLocalAddr, int iLocalPort);
    void Bind(int iLocalPort);
    
    // CloseSocket operation
    void CloseSocket();
    
    // Default: int iBackLog = 1
    void Listen(int iBackLog);
    void Accept(SocketBase *pcConnection, IPAddress &cRemoteAddr, int &iRemotePortNo);

    int  Recv(char *pBuffer, int iBufLength, unsigned int uiFlags);
    // IP Address and port number of the sender are returned in cSourceIP and iSourcePortNumber.
    int  RecvFrom(char *pBuffer, int iBufLength, unsigned int uiFlags,
                  IPAddress &cSourceIP, int &iSourcePortNumber);

    int  Send(char *pPayload, int iPayloadLength, unsigned int uiFlags);
    //The socket transmits the data payload to the specified IP address and port number.
    int  SendTo(char *pPayload, int iPayloadLength, unsigned int uiFlags,
                IPAddress &cDestinationIP, int iDestinationPortNumber);
    
    // In order to solve the reconnect problem
    void ResetSock();
    
    // Get details of the IP address and port number bound to the local socket.
    void GetSockName(IPAddress &cLocalAddr, int &iLocalPort);
    // Get details of the IP address and port number bound to the remote socket.
    void GetPeerName(IPAddress &cRemoteAddr, int &iRemotePort);

    // Get current option settings on the socket. 
    void GetSockOpt(int iCodeLevel, int iOptionName, void *pOptionData, int &iDataLength);
    // Set current option settings on the socket. 
    void SetSockOpt(int iCodeLevel, int iOptionName, const void *pOptionData, int iDataLength);

protected:
    // iSockDesc is the socket fd of the SocketBase.
    int  iSockDesc;
    
    // true for ipv6, false for ipv4. 
    bool bIPv6Socket;
    
    int iSocketProto;

    // Reset the internal socket details to meet the demand, especially for socket accept operation.
    void NewSocketDetails(int iNewSockDesc, bool bIsIPv6);
};

/******************************************************************************/
/* TCP Socket Classes.                                                        */
/******************************************************************************/
/* class TCPSocket.                                                           */
/*                                                                            */
/* The TCPSocket class provides common TCP functionality of client and server */
/* side TCP sockets within a class and provides a class from which both       */
/* TCPClientSocker and TCPServerSocket can inherit - this class inherits from */
/* the SocketBase base class.  Provision is made to both send and receive     */
/* data, as well as obtain addressing information (IP Address and port        */
/* number), both of the local and remote side of the socket.  All of these    */
/* features/methods will fail if the socket is not connected and a Socket     */
/* Exception will be thrown.  The provided methods are as follows:            */
/*                                                                            */
/* Constructor        : Create either an IPv6 or IPv4 TCP Socket, forwards    */
/*                      the call to the base class constructor.  There also   */
/*                      exists a protected constructor that allows creation   */
/*                      of a socket using an existing socket descriptor.      */
/* Destructor         : Destroy the created Socket.                           */
/* SendData()         : Send data from this socket to the remote connection.  */
/*                      Will fail if not connected.                           */
/* RecvData()         : Receive data sent to this socket from the remote      */
/*                      connection.  Will fail if not connected.              */
/* LocalIPAddress()   : If set, returns the local IP address of the socket.   */
/* RemoteIPAddress()  : If connected, returns the IP address of the remote    */
/*                      socket connection.                                    */
/* LocalPortNumber()  : If set, returns the local port number of the socket.  */
/* RemotePortNumber() : If connected, returns the port number of the remote   */
/*                      socket connection.                                    */
/* GetSockOpt()       : Provision of call through to base class method.       */
/* SetSockOpt()       : Provision of call through to base class method.       */
/*                                                                            */
/* NOTE: TCPServerSocket is made a friend of TCPSocket so that it can call    */
/*       the protected member methods of TCPSocket in the Accept() method.    */
/******************************************************************************/
class TCPSocket : public SocketBase {
    
    friend class TCPServerSocket;

public:
    // Default: bool bUseIPv6 = false
    TCPSocket(bool bUseIPv6);
    virtual ~TCPSocket() {}

    int SendData(char *pData, int iDataLen);
    int RecvData(char *pBuffer, int iBufferLen);

    int SendCompleteData(char *pData, int iDataLen);
    int RecvCompleteData(char *pBuffer, int iBufferLen);
    
    // Read or write json information from or into socket.
    cJSON* ReadJsonFromSocket();
    void   WriteJsonToSocket(cJSON *json);

    IPAddress & LocalIPAddress();
    IPAddress & RemoteIPAddress();    
    int LocalPortNumber();
    int RemotePortNumber();
    
    char* LocalHostName();
    char* RemoteHostName();

    // SetLocal and SetConnected functions obtain the local IP address and remote IP address
    // and set bLocalSet flag and bIsConnected flag.
    // SetLocal: get local ip address by GetSockName() methods 
    // SetConnected: get remote ip address by GetPeerName() methods
    void SetLocal();
    void SetConnected();

    void GetSockOpt(int iCodeLevel, int iOptionName, void *pOptionData, int &iDataLength);
    void SetSockOpt(int iCodeLevel, int iOptionName, const void *pOptionData, int iDataLength);

protected:
    // bool
    bool bLocalSet, bIsConnected;
    
    // Two address: local IP address && remote IP address.
    IPAddress cLocalAddress, cRemoteAddress;
    // Two ports: local Port && remote Port.
    int  iLocalPort, iRemotePort;    
};

/******************************************************************************/
/* class TCPClientSocket.                                                     */
/*                                                                            */
/* The TCPClientSocket class provides client based TCP functionality within a */
/* class.  This class inherits from the TCPSocket base class and provides the */
/* base functionality of a TCP client socket.  All the basic TCP methods from */
/* TCPSocket are inherited, newly provided methods are Connect() and a new    */
/* constructor which enables creation of a connected socket.  If an error     */
/* occurs at any stage, a Socket Exception is thrown.  The provided methods   */
/* are as follows:                                                            */
/*                                                                            */
/* Constructor       : Create either an IPv6 or IPv4 TCP Client Socket, there */
/*                     are two constructors.  The first creates the socket in */
/*                     a disconnected state.  The second connects the socked  */
/*                     to the specified server.                               */
/* Destructor        : Destroy the created Socket.                            */
/* ConnectServer()   : Connect the socket to the specified server and port.   */
/*                                                                            */
/* The following methods are inherited from TCPSocket:                        */
/*                                                                            */
/*    SendData()    LocalIPAddress()    RemoteIPAddress()    GetSockOpt()     */
/*    RecvData()    LocalPortNumber()   RemotePortNumber()   SetSockOpt()     */
/******************************************************************************/
class TCPClientSocket : public TCPSocket {
public:
    // Default: bool bUseIPv6 = false
    TCPClientSocket(IPAddress &cServAddr, int iServPort, bool bUseIPv6);
    // Default: bool bUseIPv6 = false
    TCPClientSocket(bool bUseIPv6);
    
    virtual ~TCPClientSocket() {
        
    }

    void ConnectServer(IPAddress &cServAddr, int iServPort);
};

/******************************************************************************/
/* class TCPServerSocket.                                                     */
/*                                                                            */
/* The TCPServerSocket class provides server based TCP functionality within a */
/* class.  This class inherits from the TCPSocket base class and provides the */
/* base functionality of a TCP server socket.  All the basic TCP methods from */
/* TCPSocket are inherited, newly provided methods are Accept() and new       */
/* constructors which enable creation of a listening server socket where the  */
/* bound IP Address is either specified or a wildcard and the bound port      */
/* number is either specified or a wildcard.  If an error occurs at any       */
/* stage, a Socket Exception is thrown.  The provided methods are as follows: */
/* are as follows:                                                            */
/*                                                                            */
/* Constructor    : Create either an IPv6 or IPv4 TCP Server Socket, there    */
/*                  are two constructors.  One constructor offers the option  */
/*                  of specifying an IP Address to bind the listening socket  */
/*                  to, the other will bind to the wildcard IP Address.  The  */
/*                  other options are common to both constructors. iLocalPort */
/*                  specifies the port number bound to the listening socket,  */
/*                  a value of zero means the operating system will choose    */
/*                  this value, it can be obtained by calling the base class  */
/*                  LocalPortNumber() method.  iBackLog indicates the maximum */
/*                  number of pending connections. bUseIPv6 specifies whether */
/*                  the socket will use IPv4 or IPv6.                         */
/* Destructor     : Destroy the created Socket.                               */
/* AcceptClient() : Accepts a pending connection on the listening server      */
/*                  socket.  Creates a TCPSocket instance to refer to the     */
/*                  newly created socket for future communications to that    */
/*                  client.  A pointer to the TCPSocket instance is returned. */
/*                  This pointer must be deleted to close the socket with the */
/*                  client.                                                   */
/*                                                                            */
/* The following methods are inherited from TCPSocket:                        */
/*                                                                            */
/*    SendData()    LocalIPAddress()    RemoteIPAddress()    GetSockOpt()     */
/*    RecvData()    LocalPortNumber()   RemotePortNumber()   SetSockOpt()     */
/******************************************************************************/
class TCPServerSocket : public TCPSocket {

public:
    // Default: IPAddress &cLocalAddr, int iLocalPort = 0, int iBackLog = 1, bool bUseIPv6 = false
    TCPServerSocket(IPAddress &cLocalAddr, int iLocalPort,
                    int iBackLog, bool bUseIPv6);
    // Default: int iLocalPort = 0, int iBackLog = 1, bool bUseIPv6 = false
    TCPServerSocket(int iLocalPort, int iBackLog,
                    bool bUseIPv6);
                    
    // Default: bool bUseIPv6 = false
    TCPServerSocket(bool bUseIPv6);
    
    virtual ~TCPServerSocket() {
        
    }

    // Return value is allocated in heap, we must release it after usage.
    TCPSocket * AcceptClient();
};

/******************************************************************************/
/* UDP Socket Classes.                                                        */
/******************************************************************************/
/* class UDPSocket.                                                           */
/*                                                                            */
/* The UDPSocket class provides client based UDP functionality within a       */
/* class.  This class inherits from the SocketBase base class and provides    */
/* only the base functionality of a UDP client socket.  If any error occurs,  */
/* a Socket Exception is thrown.  The provided methods are as follows:        */
/*                                                                            */
/* Constructor       : Create either an IPv6 or IPv4 Socket.                  */
/* Destructor        : Destroy the created Socket.                            */
/* SendDatagram()    : Send a Datagram from this socket to the provided       */
/*                     destination IP Address and Port Number.                */
/* ReceiveDatagram() : Receive a datagram sent to this socket.  The source IP */
/*                     Address and Port Number are stored in the provided     */
/*                     variables.                                             */
/* GetSockOpt()      : Provision of call through to base class method.        */
/* SetSockOpt()      : Provision of call through to base class method.        */
/******************************************************************************/
class UDPSocket : public SocketBase {

public:
    // Default: bool bUseIPv6 = false
    UDPSocket(bool bUseIPv6);
    
    virtual ~UDPSocket() {
        
    }

    int SendDatagram(char *pBuffer, int iBufLength,
                     IPAddress &cDestAddr, int iDestPort);
    int ReceiveDatagram(char *pBuffer, int iBufLength,
                        IPAddress &cSourceAddr, int &iSourcePort);

    void GetSockOpt(int iCodeLevel, int iOptionName, void *pOptionData, int &iDataLength);
    void SetSockOpt(int iCodeLevel, int iOptionName, const void *pOptionData, int iDataLength);
};

/******************************************************************************/
/* class UDPServerSocket.                                                     */
/*                                                                            */
/* The UDPServerSocket class provides server based UDP functionality within   */
/* a class.  This class inherits from the UDPSocket base class and provides   */
/* the base functionality of a Server side UDP Socket.  The Send and Receive  */
/* data methods are inherited from UDPSocket, the constructor requires the    */
/* provision of local port number and IP Address to bind to.  If an error     */
/* occurs at any stage, a Socket Exception is thrown.  The provided methods   */
/* are as follows:                                                            */
/*                                                                            */
/* Constructor        : Create either an IPv6 or IPv4 Server Socket on the    */
/*                      specified port.  Two constructors are available, the  */
/*                      first binds the socket to the specified local IP      */
/*                      Address and port number, the second to all local IP   */
/*                      Addresses and the specified port number.  The default */
/*                      port number of zero means that the system chooses the */
/*                      the port number of the socket.                        */
/* Destructor        : Destroy the created Socket.                            */
/* SendDatagram()    : Inherited from UDPSocket with the same parameters.     */
/* ReceiveDatagram() : Inherited from UDPSocket with the same parameters.     */
/* LocalIPAddress()  : If connected, returns the local IP address of the      */
/*                     connected socket.                                      */
/* LocalPortNumber() : If connected, returns the local port number of the     */
/*                     connected socket.                                      */
/******************************************************************************/
class UDPServerSocket : public UDPSocket {

public:
    // Default: IPAddress &cLocalAddr, int iLocalPortNo = 0, bool bUseIPv6 = false
    UDPServerSocket(IPAddress &cLocalAddr, int iLocalPortNo,
                    bool bUseIPv6);
    UDPServerSocket(int iLocalPortNo, bool bUseIPv6);
    
    // Default: bool bUseIPv6 = false
    UDPServerSocket(bool bUseIPv6);
    
    virtual ~UDPServerSocket() {
        
    }

    IPAddress & LocalIPAddress() { 
        return cLocalAddress;  
    }

    char * LocalHostName() {
        return (char *)cLocalAddress;
    }
    
    int LocalPortNumber() { 
        return iLocalPort;  
    }

protected:
    IPAddress cLocalAddress;
    int       iLocalPort;
};

/******************************************************************************/
/* class UDPConnectedSocket.                                                  */
/*                                                                            */
/* The UDPConnectedSocket class provides client based UDP functionality       */
/* within a class.  This class inherits from the SocketBase base class and    */
/* provides the base functionality of a connected UDP Socket.  Data can only  */
/* be sent or received once the socket has been connected and can only be     */
/* sent to or received from the server the socket is connected to.  There is  */
/* provision to connect and disconnect the socket as well as obtaining        */
/* information about the local and remote IP addresses and port numbers.  If  */
/* an error occurs at any stage, a Socket Exception is thrown.  The provided  */
/* methods are as follows:                                                    */
/*                                                                            */
/* Constructor        : Create either an IPv6 or IPv4 Connected Socket, two   */
/*                      constructors are available, the first creates the     */
/*                      socket in a disconnected state, the second connects   */
/*                      to the specified server.                              */
/* Destructor         : Destroy the created Socket.                           */
/* Connect()          : Connect the socket to the specified server and port.  */
/* DisConnect()       : Disconnect the socket, can no longer send or receive  */
/*                      data.  This is not necessary when destroying the      */
/*                      socket, the destructor will handle any necessary      */
/*                      clean-up.                                             */
/* SendDatagram()     : Send a Datagram from this socket to the connected     */
/*                      server.  Will fail if not connected.                  */
/* ReceiveDatagram()  : Receive a datagram sent to this socket from the       */
/*                      connected server.  Will fail if not connected.        */
/* LocalIPAddress()   : If connected, returns the local IP address of the     */
/*                      connected socket.                                     */
/* RemoteIPAddress()  : If connected, returns the server IP address of the    */
/*                      connected socket.                                     */
/* LocalPortNumber()  : If connected, returns the local port number of the    */
/*                      connected socket.                                     */
/* RemotePortNumber() : If connected, returns the server port number of the   */
/*                      connected socket.                                     */
/* GetSockOpt()       : Provision of call through to base class method.       */
/* SetSockOpt()       : Provision of call through to base class method.       */
/******************************************************************************/
class UDPConnectedSocket : public SocketBase {
public:
    // Default: bool bUseIPv6 = false
    UDPConnectedSocket(bool bUseIPv6);
    UDPConnectedSocket(IPAddress &cServAddr, int iServPortNo, bool bUseIPv6);
    
    virtual ~UDPConnectedSocket() {
        
    }

    void Connect(IPAddress &cServAddr, int iServPortNo);
    void DisConnect();

    int  SendDatagram(char *pBuffer, int iBufLength);
    int  ReceiveDatagram(char *pBuffer, int iBufLength);

    IPAddress & LocalIPAddress() { 
        return cLocalAddress;  
    }
    
    IPAddress & RemoteIPAddress() { 
        return cServerAddress; 
    }
    
    char* LocalHostName() {
        return (char *)cLocalAddress;
    }
    
    char* RemoteHostName() {
        return (char *)cServerAddress;
    }
    
    int  LocalPortNumber() { 
        return iLocalPort;  
    }
    
    int  RemotePortNumber() { 
        return iServerPort; 
    }
    
    bool IsConnected() {
        return bIsConnected;
    }

    void GetSockOpt(int iCodeLevel, int iOptionName, void *pOptionData, int &iDataLength);
    void SetSockOpt(int iCodeLevel, int iOptionName, const void *pOptionData, int iDataLength);

protected:
    bool bIsConnected;
    IPAddress cLocalAddress, cServerAddress;
    int  iLocalPort, iServerPort;
};

#endif

/******************************************************************************/
/* End of File: socketClass.h                                                    */
/******************************************************************************/
